
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "examples.h"
#include "xrn_crypto.h"
#include "xrn_core.h"
#include "lorem_ipsum.h"

    /////////////////////////////////////////////////////
    //                   Introduction                  //
    /////////////////////////////////////////////////////
    // This code example shows how to generate and     //
    // verify asymmetric certificates.                 //
    /////////////////////////////////////////////////////

    /////////////////////////////////////////////////////
    //                   Pre-requisits                 //
    /////////////////////////////////////////////////////
    // The Xoron matrix decompressed data structure    //
    // needs to be mined before running this code      //
    // example. Some examples on how to mine Xoron     //
    // matrices can be found in                        //
    // generate_xrn_matrix_all_rnd.c or                //
    // generate_xrn_matrix_one_third.c                 //
    //                                                 //
    // One monomial key.                               //
    // Two binomial keys.                              //
    //                                                 //
    // An example on how to generate keys can be found //
    // in generate_keys_with_wrapper_functions.c       //
    /////////////////////////////////////////////////////

int generate_binomial_key_bob_certificates_asymmetric(
 )
{

    FILE *bob_binomial_key_fp;
    xbinomial_key_t bob_binomial_key;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    /////////////////////////////
    // Variable initialization //
    /////////////////////////////

    // Initialize default run time settings
    // In this code example only the settings.rnd_str is used
    // In the xrn_load_default_settings function xrn_make_certificate_asymmetric_wrapper string is used.
    // Other functions names can be also used to initialize settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // generate a random binomial key

    if ( XSUCCESS != xrn_initialize_true_rnd_num( settings.rnd_str, &bob_binomial_key.start ) ) {
        return -1;
    }

    if ( XSUCCESS != xrn_initialize_true_rnd_num( settings.rnd_str, &bob_binomial_key.end ) ) {
        return -1;
    }

    // store binomial key

    bob_binomial_key_fp = fopen( "bob_binomial_key.xf", "wb" );
    if ( bob_binomial_key_fp == NULL ) {
        return -1;
    }

    if ( XSUCCESS != xrn_dump_binomial_key( bob_binomial_key, bob_binomial_key_fp, settings ) ) {
        fclose( bob_binomial_key_fp );
        return -1;
    }

    if ( 0 != fclose( bob_binomial_key_fp ) ) {
        return -1;
    }

    return 0;

}

int xrn_certificate_asymmetric_generation_wrapper(
 )
{
    //////////////////////////
    // Variable definitions //
    //////////////////////////

    FILE *decompressed_xrn_matrix_fp;
    FILE *alice_binomial_key_fp;
    FILE *alice_monomial_key_fp;
    FILE *bob_binomial_key_fp;
    FILE *certificate_fp;

    uint64_t start_validity;
    uint64_t end_validity;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // Initialize validities
    start_validity = ( uint64_t ) time( 0 );
    end_validity = ( uint64_t ) time( 0 ) + 10; // add ten seconds to current time

    alice_monomial_key_fp = fopen( "xmonomial_key.xf", "rb" );
    alice_binomial_key_fp = fopen( "xbinomial_key.xf", "rb" );
    bob_binomial_key_fp = fopen( "bob_binomial_key.xf", "rb" );
    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    certificate_fp = fopen( "certificate.xf", "wb" );

    if ( ( certificate_fp == NULL ) || ( alice_binomial_key_fp == NULL ) || ( alice_monomial_key_fp == NULL )
         || ( bob_binomial_key_fp == NULL )
         || ( decompressed_xrn_matrix_fp == NULL ) ) {
        return -1;
    }

    /////////////////////////
    // Generate common key //
    /////////////////////////

    if ( XSUCCESS != xrn_make_certificate_asymmetric_wrapper( alice_monomial_key_fp,    // issuer monomial key file pointer
                                                              alice_binomial_key_fp,    // issuer binomial key file pointer
                                                              bob_binomial_key_fp,      // subject binomial key file pointer
                                                              "BOB",    // subject string
                                                              decompressed_xrn_matrix_fp,       // Xoron matrix key file pointer
                                                              start_validity,   // start of the validity
                                                              end_validity,     // end of the validity
                                                              certificate_fp,   // output certificate file pointer
                                                              settings  // run time settings
          ) ) {

        fclose( alice_monomial_key_fp );
        fclose( alice_binomial_key_fp );
        fclose( decompressed_xrn_matrix_fp );
        fclose( bob_binomial_key_fp );
        fclose( certificate_fp );
        return -1;
    }

    if ( ( 0 != fclose( alice_monomial_key_fp ) ) || ( 0 != fclose( alice_binomial_key_fp ) )
         || ( 0 != fclose( decompressed_xrn_matrix_fp ) )
         || ( 0 != fclose( bob_binomial_key_fp ) ) || ( 0 != fclose( certificate_fp ) ) ) {
        return -1;
    }

    // An alternative way to perform the same computation can be achieved using the xrn_make_certificate_asymmetric function
    // if ( XSUCCESS != xrn_make_certificate_asymmetric( alice_monomial_key, // alice_monomial_key is of the type ( xmonomial_key_t )
    //                                          alice_binomial_key, // alice_binomial_key is of the type ( xbinomial_key_t )
    //                                          bob_binomial_key, // bob_binomial_key is of the type ( xbinomial_key_t )
    //                                          "BOB",
    //                                          xrn_matrix, // xrn_matrix is of the type ( xrn_matrix_t * )
    //                                          start_validity,
    //                                          end_validity,
    //                                          certificate, // certificate is of the type ( xcertificate_asy_t * )
    //                                          settings
    //       ) ) {

    return 0;
}

int xrn_certificate_asymmetric_verification_wrapper(
 )
{
    //////////////////////////
    // Variable definitions //
    //////////////////////////

    FILE *decompressed_xrn_matrix_fp;
    FILE *alice_binomial_key_fp;
    FILE *certificate_fp;

    // library run time settings

    xrn_crypto_extra_settings_t settings;

    // all the subfields of settings, can be found in xrn_crypto_extra_settings_t.txt

    //////////////////////////
    // Initialize variables //
    //////////////////////////

    // Initialize default run time settings

    if ( XSUCCESS != xrn_load_default_settings( &settings ) ) {
        return -1;
    }

    // Initialize validities

    alice_binomial_key_fp = fopen( "xbinomial_key.xf", "rb" );
    decompressed_xrn_matrix_fp = fopen( "xrn_matrix.xm", "rb" );
    certificate_fp = fopen( "certificate.xf", "rb" );

    if ( ( alice_binomial_key_fp == NULL ) || ( decompressed_xrn_matrix_fp == NULL )
         || ( certificate_fp == NULL ) ) {
        return -1;
    }

    /////////////////////////
    // Generate common key //
    /////////////////////////

    if ( XSUCCESS != xrn_check_certificate_asymmetric_wrapper( alice_binomial_key_fp,   // issuer binomial key file pointer
                                                               decompressed_xrn_matrix_fp,      // Xoron matrix key file pointer
                                                               certificate_fp,  // certificate file pointer
                                                               settings // run time settings
          ) ) {

        fclose( decompressed_xrn_matrix_fp );
        fclose( certificate_fp );
        fclose( alice_binomial_key_fp );

        return -1;
    }

    if ( ( 0 != fclose( alice_binomial_key_fp ) ) || ( 0 != fclose( decompressed_xrn_matrix_fp ) )
         || ( 0 != fclose( certificate_fp ) ) ) {
        return -1;
    }

    // An alternative way to perform the same computation can be achieved using the xrn_check_certificate_asymmetric function
    // if ( XSUCCESS != xrn_check_certificate_asymmetric( alice_binomial_key, // alice_binomial_key is of the type ( xbinomial_key_t )
    //                                          xrn_matrix, // xrn_matrix is of the type ( xrn_matrix_t * )
    //                                          certificate, // certificate is of the type ( xcertificate_asy_t )
    //                                          settings
    //       ) ) {

    return 0;
}

int certificate_asymmetric(
 )
{

    /////////////
    // Logging //
    /////////////

    // Set the default logging file streams
    // errors -> stderr
    // warnings -> stdout
    // notifications -> stdout
    // debug -> stdout

    xrn_set_default_log(  );

    // To change the default logging you can use the functions below,
    // where fp is the opened file pointer
    // 
    // xrn_change_error_log( fp )
    // xrn_change_warning_log( fp )
    // xrn_change_notification_log( fp )
    // xrn_change_debug_log( fp )

    if ( 0 != generate_binomial_key_bob_certificates_asymmetric(  ) ) {
        return -1;
    }

    printf( "compute certificate ... \n" );
    if ( 0 != xrn_certificate_asymmetric_generation_wrapper(  ) ) {
        printf( "error in certificate generation \n" );
        return -1;
    }

    printf( "certificate generated \n" );

    if ( 0 != xrn_certificate_asymmetric_verification_wrapper(  ) ) {
        printf( "error in certificate verification \n" );
        return -1;
    }

    printf( "certificate verified \n" );

    return 0;

}

